/* ------------------------------------------------------------------------*
 * spi
 * ------------------------------------------------------------------------*/
#include "bsp_spi_com.h"
#include "bsp.h" 
#include "bsp_dma.h" 
#include "pincfg.h" 

#define SPIX       SPI1
#define ISR_IRQn   SPI1_IRQn

static uint8_t dma_fixed_dat;
static volatile uint8_t dma_comp;
static void spi_dma_call_back(int err);

/*****************************************************************************
* @brief   hal init.
* @param   none
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void com_spi_init(void)
{
	SPI_Open(SPIX, SPI_MASTER, SPI_MODE_0, SPII2S_DATABIT_8, 24000000);
	// 帧间隔
	SPIX->CTL = (SPIX->CTL & ~SPI_CTL_SUSPITV_Msk) | (1UL << SPI_CTL_SUSPITV_Pos);
	
	// SS
	spi1_ss.dir_out_pp();
	spi1_ss.en();
}

/*****************************************************************************
* @brief   cs ctr.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void com_cs(uint8_t st)
{
	if(st)
		spi1_ss.en();
	else
		spi1_ss.dis();
}

/*****************************************************************************
* @brief   spi speed.
*****************************************************************************/
void com_spi_high_speed(void)
{
	SPIX->CLKDIV = 3-1;
}

/*****************************************************************************
* @brief   spi speed.
*****************************************************************************/
void com_spi_low_speed(void)
{
	SPIX->CLKDIV = 8-1;
}

/*****************************************************************************
* @brief   spi delay.
*****************************************************************************/
#define com_spi_read_delay()	NOP1()
#define spi_wait_rst_comp()		while(SPIX->STATUS & SPI_STATUS_TXRXRST_Msk){}
#define spi_rx_reset()			SPIX->FIFOCTL |= SPI_FIFOCTL_RXRST_Msk

/*****************************************************************************
* @brief   spi data read and write.             
* @param   data
* @return  data
* @ Pass/ Fail criteria: none
*****************************************************************************/
uint8_t com_spi_rw(uint8_t dataW)
{
	spi_wait_rst_comp();

	//send data
	SPI_WRITE_TX(SPIX, dataW);
	com_spi_read_delay();
	
	//wait for trans complete
	while (SPI_IS_BUSY(SPIX)){}
	
    return SPI_READ_RX(SPIX);
}

/*****************************************************************************
* @brief   spi data read and write.             
* @param   data
* @return  data
* @ Pass/ Fail criteria: none
*****************************************************************************/
uint32_t com_spi_rw_bits(uint32_t dataW, uint8_t bits)
{
	uint32_t rdat;
	
	spi_wait_rst_comp();
	
	SPI_SET_DATA_WIDTH(SPIX, bits);
	
	//send data
	SPI_WRITE_TX(SPIX, dataW);
	com_spi_read_delay();
	
	//wait for trans complete
	while (SPI_IS_BUSY(SPIX)){}
	
	rdat = SPI_READ_RX(SPIX);
	
	SPI_SET_DATA_WIDTH(SPIX, 8);
		
    return rdat;
}

/*****************************************************************************
* @brief   spi data read.
*****************************************************************************/
#define SPI_READ_U8()	if((SPIX->STATUS & SPI_STATUS_RXEMPTY_Msk) == 0) *datar++ = SPI_READ_RX(SPIX)
#define SPI_READ_U32()	if((SPIX->STATUS & SPI_STATUS_RXEMPTY_Msk) == 0) *prd32++ = SPI_READ_RX(SPIX)
uint8_t com_spi_read(uint8_t *datar, uint32_t Len)
{
	char dma_ch_rx=-1, dma_ch_tx=-1;
	pdma_basic_cfg_type dma_cfg;
		
	spi_wait_rst_comp();
   
	// 数量较大时用DMA
	if(Len > 20)
	{
		dma_fixed_dat = 0xFF;
		
		// dma 申请配置
		dma_ch_rx = bsp_pdma_alloc();
		dma_ch_tx = bsp_pdma_alloc();
		
		if(dma_ch_rx >= 0 && dma_ch_tx >= 0)
		{
			// 复位SPI PDMA电路
			SPIX->PDMACTL = SPI_PDMACTL_PDMARST_Msk;
			
			// 通道配置
			dma_cfg.req_src = PDMA_SPI1_TX,
			dma_cfg.prio = 0,
			dma_cfg.int_en = 0,
			dma_cfg.ctr_sa_mode = PDMA_SAR_FIX,
			dma_cfg.ctr_da_mode = PDMA_DAR_FIX,
			dma_cfg.ctr_txt_mode = PDMA_REQ_SINGLE,
			dma_cfg.ctr_width = PDMA_WIDTH_8,
			dma_cfg.ctr_amount = Len -1,
			dma_cfg.sa = (uint32_t)&dma_fixed_dat,
			dma_cfg.da = (uint32_t)(&SPIX->TX),
			dma_cfg.call_back = 0;
			bsp_pdma_cfg(&dma_cfg, dma_ch_tx);
			
			dma_cfg.req_src = PDMA_SPI1_RX,
			dma_cfg.prio = 0,
			dma_cfg.int_en = 1,
			dma_cfg.ctr_sa_mode = PDMA_SAR_FIX,
			dma_cfg.ctr_da_mode = PDMA_DAR_INC,
			dma_cfg.ctr_txt_mode = PDMA_REQ_SINGLE,
			dma_cfg.ctr_width = PDMA_WIDTH_8,
			dma_cfg.ctr_amount = Len - 1,
			dma_cfg.sa = (uint32_t)(&SPIX->RX),
			dma_cfg.da = (uint32_t)(datar),
			dma_cfg.call_back = spi_dma_call_back;
			bsp_pdma_cfg(&dma_cfg, dma_ch_rx);
			
			// 开启DMA请求
			dma_comp = 0;
			SPIX->PDMACTL = SPI_PDMACTL_TXPDMAEN_Msk;
			__DSB();
			SPIX->PDMACTL = SPI_PDMACTL_RXPDMAEN_Msk | SPI_PDMACTL_TXPDMAEN_Msk;
			
			while(!dma_comp){}
				
			bsp_pdma_free(dma_ch_rx);
			bsp_pdma_free(dma_ch_tx);
				
			// 复位SPI PDMA电路
			SPIX->PDMACTL = SPI_PDMACTL_PDMARST_Msk;
			
			Len = 0;
		}
		else
		{
			// DMA 申请失败
			if(dma_ch_rx >= 0)
				bsp_pdma_free(dma_ch_rx);
			if(dma_ch_tx >= 0)
				bsp_pdma_free(dma_ch_tx);			
		}
	}
	
	// DMA 不成功 Len不变
	if(Len)
	{
		// 软件收发
		while (Len--)
		{
			//send data
			SPI_WRITE_TX(SPIX, 0xFF);
			com_spi_read_delay();
			
			// rx not empty ## read data
			SPI_READ_U8();

			//wait for tx fifo
			while (SPI_GET_TX_FIFO_FULL_FLAG(SPIX)) SPI_READ_U8();
		}
		
		//wait for trans complete
		while (SPI_IS_BUSY(SPIX)) SPI_READ_U8();
		
		// rx not empty ## read data
		SPI_READ_U8();
	}

    return 0;
}

/*****************************************************************************
* @brief   spi data write.
*****************************************************************************/
uint8_t com_spi_write(uint8_t *dataw, uint32_t Len)
{
	char dma_ch_rx=-1, dma_ch_tx=-1;
	pdma_basic_cfg_type dma_cfg;
		
	spi_wait_rst_comp();
   
	// 数量较大时用DMA
	if(Len > 20)
	{
		dma_fixed_dat = 0xFF;
		
		// dma 申请配置
		dma_ch_rx = bsp_pdma_alloc();
		dma_ch_tx = bsp_pdma_alloc();
		
		if(dma_ch_rx >= 0 && dma_ch_tx >= 0)
		{
			// 复位SPI PDMA电路
			SPIX->PDMACTL = SPI_PDMACTL_PDMARST_Msk;
			
			// 通道配置
			dma_cfg.req_src = PDMA_SPI1_TX,
			dma_cfg.prio = 0,
			dma_cfg.int_en = 0,
			dma_cfg.ctr_sa_mode = PDMA_SAR_INC,
			dma_cfg.ctr_da_mode = PDMA_DAR_FIX,
			dma_cfg.ctr_txt_mode = PDMA_REQ_SINGLE,
			dma_cfg.ctr_width = PDMA_WIDTH_8,
			dma_cfg.ctr_amount = Len -1,
			dma_cfg.sa = (uint32_t)dataw,
			dma_cfg.da = (uint32_t)(&SPIX->TX),
			dma_cfg.call_back = 0;
			bsp_pdma_cfg(&dma_cfg, dma_ch_tx);
			
			dma_cfg.req_src = PDMA_SPI1_RX,
			dma_cfg.prio = 0,
			dma_cfg.int_en = 1,
			dma_cfg.ctr_sa_mode = PDMA_SAR_FIX,
			dma_cfg.ctr_da_mode = PDMA_DAR_FIX,
			dma_cfg.ctr_txt_mode = PDMA_REQ_SINGLE,
			dma_cfg.ctr_width = PDMA_WIDTH_8,
			dma_cfg.ctr_amount = Len - 1,
			dma_cfg.sa = (uint32_t)(&SPIX->RX),
			dma_cfg.da = (uint32_t)(&dma_fixed_dat),
			dma_cfg.call_back = spi_dma_call_back;
			bsp_pdma_cfg(&dma_cfg, dma_ch_rx);
			
			// 开启DMA请求
			dma_comp = 0;
			SPIX->PDMACTL = SPI_PDMACTL_TXPDMAEN_Msk;
			__DSB();
			SPIX->PDMACTL = SPI_PDMACTL_RXPDMAEN_Msk | SPI_PDMACTL_TXPDMAEN_Msk;
			
			while(!dma_comp){}
				
			bsp_pdma_free(dma_ch_rx);
			bsp_pdma_free(dma_ch_tx);
				
			Len = 0;
			
			// clear RX buffer
			spi_rx_reset();
			// 复位SPI PDMA电路
			SPIX->PDMACTL = SPI_PDMACTL_PDMARST_Msk;
		}
		else
		{
			// DMA 申请失败
			if(dma_ch_rx >= 0)
				bsp_pdma_free(dma_ch_rx);
			if(dma_ch_tx >= 0)
				bsp_pdma_free(dma_ch_tx);			
		}
	}
	
	// DMA 不成功 Len不变
	if (Len)
	{
		while (Len--)
		{
			//send data
			SPI_WRITE_TX(SPIX, *dataw++);
			com_spi_read_delay();

			//wait for trans complete
			while (SPI_GET_TX_FIFO_FULL_FLAG(SPIX));
		}

		//wait for trans complete
		while (SPI_IS_BUSY(SPIX));
		
		// clear RX buffer
		spi_rx_reset();		
	}
	
    return (0);
}

/*****************************************************************************
* @brief   DMA 完成
*****************************************************************************/
void spi_dma_call_back(int err)
{
	dma_comp = 1;
}
